import numpy as np
from typing import List, Dict, Tuple, Optional

class AHPModel:
    """AHP层次分析法模型"""
    
    def __init__(self, criteria_names: List[str]):
        """初始化AHP模型"""
        self.criteria_names = criteria_names
        self.criteria_matrix = None
        self.weights = None
    
    def set_criteria_matrix(self, matrix: np.ndarray) -> None:
        """设置准则层判断矩阵"""
        self.criteria_matrix = np.array(matrix)
        n = len(self.criteria_matrix)
        
        # 验证矩阵是否为方阵且满足互反性
        if self.criteria_matrix.shape != (n, n):
            raise ValueError("判断矩阵必须是方阵")
        
        for i in range(n):
            for j in range(n):
                if abs(self.criteria_matrix[i, j] * self.criteria_matrix[j, i] - 1) > 1e-10:
                    raise ValueError(f"判断矩阵不满足互反性: A[{i},{j}] = {self.criteria_matrix[i, j]}, A[{j},{i}] = {self.criteria_matrix[j, i]}")
    
    def is_consistent(self) -> bool:
        """检查判断矩阵的一致性"""
        if self.criteria_matrix is None:
            raise ValueError("请先设置判断矩阵")
        
        n = len(self.criteria_matrix)
        from numpy.linalg import eig
        
        # 计算特征值和特征向量
        eigenvalues, eigenvectors = eig(self.criteria_matrix)
        max_eigenvalue = max(eigenvalues).real
        
        # 计算一致性指标
        CI = (max_eigenvalue - n) / (n - 1)
        
        # 随机一致性指标(RI)查表
        RI_dict = {1: 0, 2: 0, 3: 0.58, 4: 0.90, 5: 1.12, 
                   6: 1.24, 7: 1.32, 8: 1.41, 9: 1.45}
        RI = RI_dict.get(n, 0)
        
        # 计算一致性比率
        CR = CI / RI if RI != 0 else 0
        
        # 保存最大特征值和CR值供外部使用
        self.max_eigenvalue = max_eigenvalue
        self.CI = CI
        self.CR = CR
        
        return CR < 0.1  # 一般认为CR<0.1时一致性可接受
    
    def get_weights(self) -> np.ndarray:
        """计算准则权重"""
        if self.criteria_matrix is None:
            raise ValueError("请先设置判断矩阵")
        
        n = len(self.criteria_matrix)
        
        # 列归一化
        normalized_matrix = np.zeros((n, n))
        for j in range(n):
            col_sum = np.sum(self.criteria_matrix[:, j])
            for i in range(n):
                normalized_matrix[i, j] = self.criteria_matrix[i, j] / col_sum
        
        # 行平均法计算权重
        self.weights = np.mean(normalized_matrix, axis=1)
        
        # 归一化权重
        self.weights = self.weights / np.sum(self.weights)
        
        return self.weights
    
    def improve_consistency(self, max_iterations=10, epsilon=0.01):
        """迭代调整判断矩阵以提高一致性"""
        if self.criteria_matrix is None:
            raise ValueError("请先设置判断矩阵")
        
        matrix = self.criteria_matrix.copy()
        n = len(matrix)
        
        for iteration in range(max_iterations):
            # 计算当前一致性
            from numpy.linalg import eig
            eigenvalues, _ = eig(matrix)
            max_eigenvalue = max(eigenvalues).real
            CI = (max_eigenvalue - n) / (n - 1)
            RI_dict = {1: 0, 2: 0, 3: 0.58, 4: 0.90, 5: 1.12, 
                       6: 1.24, 7: 1.32, 8: 1.41, 9: 1.45}
            CR = CI / RI_dict.get(n, 0)
            
            if CR < 0.1:
                self.criteria_matrix = matrix
                print(f"矩阵一致性已改善: CR = {CR:.4f}")
                return True
            
            # 找出最不一致的元素并调整
            max_inconsistency = 0
            i_max, j_max = 0, 0
            
            for i in range(n):
                for j in range(i+1, n):
                    # 检查传递性
                    for k in range(n):
                        if i != k and j != k:
                            # 计算传递性比率
                            ratio = matrix[i, j] * matrix[j, k] / matrix[i, k]
                            inconsistency = abs(ratio - 1)
                            
                            if inconsistency > max_inconsistency:
                                max_inconsistency = inconsistency
                                i_max, j_max = i, j
            
            # 调整最不一致的元素
            if max_inconsistency > epsilon:
                # 简化调整：向传递性方向移动一小步
                # 例如：如果 a_ij * a_jk > a_ik，则增加 a_ik
                # 这里使用简单的平均调整
                adjustment_factor = 1.05  # 调整步长
                
                for k in range(n):
                    if i_max != k and j_max != k:
                        desired = matrix[i_max, j_max] * matrix[j_max, k]
                        current = matrix[i_max, k]
                        
                        if desired > current:
                            matrix[i_max, k] *= adjustment_factor
                            matrix[k, i_max] = 1 / matrix[i_max, k]
                        else:
                            matrix[i_max, k] /= adjustment_factor
                            matrix[k, i_max] = 1 / matrix[i_max, k]
            
            else:
                break  # 没有显著不一致，退出
        
        # 重新计算最终一致性
        eigenvalues, _ = eig(matrix)
        max_eigenvalue = max(eigenvalues).real
        CI = (max_eigenvalue - n) / (n - 1)
        CR = CI / RI_dict.get(n, 0)
        
        self.criteria_matrix = matrix
        print(f"迭代调整后一致性: CR = {CR:.4f}")
        
        return CR < 0.1